.TH "transapi_tutorial" 3 "Thu Feb 6 2014" "Version 0.7.0" "libnetconf" \" -*- nroff -*-
.ad l
.nh
.SH NAME
transapi_tutorial \- transAPI Tutorial 
On this page we will show how to write a simple module for controlling \fCexample toaster\fP\&. 
.PP
\fBNote:\fP
.RS 4
To install libnetconf follow the instructions on the \fBCompilation and Installation\fP page\&.
.RE
.PP
.SS "Preparations"
.PP
In this example we will work with the data model of the toaster provided by Andy Bierman at NETCONF CENTRAL (http://dld.netconfcentral.org/src/toaster@2009-11-20.yang)\&.
.PP
First, we need to identify important parts of the configuration data\&. Since the toaster data model describes only one configurable element, we have an easy choice\&. So, we can create the 'paths_file' file containing the specification of our chosen element and mapping prefixes with URIs for any used namespace\&.
.PP
Our file may look like this (irrespective of order): 
.PP
.nf
toaster=http://netconfcentral\&.org/ns/toaster
/toaster:toaster

.fi
.PP
.PP
.SS "Generating code"
.PP
.IP "1." 4
Create a new directory for the toaster module and move the data model and the path file into it: 
.PP
.nf
$ mkdir toaster && cd toaster/
$ mv \&.\&./toaster@2009-11-20\&.yang \&.\&./paths_file \&.

.fi
.PP

.IP "2." 4
Run `lnctool' for transapi: 
.PP
.nf
$ lnctool --model \&./toaster@2009-11-20\&.yang transapi --paths \&./paths_file

.fi
.PP

.PP
.PP
Besides the generated source code of our transAPI module and GNU Build System files (Makefile\&.in, configure\&.in,\&.\&.\&.), lnctool also generates YIN format of the data model and validators accepted by the libnetconf's \fBncds_new_transapi()\fP and \fBncds_set_validation()\fP functions:
.IP "\(bu" 2
*\&.yin - YIN format of the data model
.IP "\(bu" 2
*\&.rng - RelagNG schema for syntax validation
.IP "\(bu" 2
*-schematron\&.xsl - Schematron XSL stylesheet for semantics validation
.PP
.PP
.SS "Filling up functionality"
.PP
Here we show the simplest example of a toaster simulating module\&. It is working but does not deal with multiple access and threads correctly\&. Better example may can be found in the netopeer-server-sl source codes located in the \fCNetopeer project\fP repository (server-sl/toaster/toaster\&.c)\&.
.PP
.IP "1." 4
Open 'toaster\&.c' file with your favorite editor: 
.PP
.nf
$ vim toaster\&.c

.fi
.PP

.IP "2." 4
Add global variables and auxiliary functions 
.PP
.nf
enum {ON, OFF, BUSY} status;
pthread_t thread;

void * auxiliary_make_toast(void * time)
{
        sleep(*(int*)time);

        if (status == BUSY) {
                status = ON;
                ncntf_event_new(-1, NCNTF_GENERIC, "<toastDone><toastStatus>done</toastStatus></toastDone>");
        }
        return(NULL);
}

.fi
.PP

.IP "3." 4
Complete the 'transapi_init()' function with actions that will be run right after the module loads and before any other function in the module is called\&. We ignore the XML document pointer, since we wish the toaster to be always off when loading this module\&. 
.PP
.nf
int transapi_init(xmlDocPtr * running)
{
        status = OFF;
        printf("Toaster initialized!\n");
        return(EXIT_SUCCESS);
}

.fi
.PP

.IP "4." 4
Locate the 'transapi_close()' function and fill it with actions that will be run just before the module unloads\&. No other function will be called after 'transapi_close()'\&. 
.PP
.nf
void transapi_close()
{
        printf("Toaster ready for unplugging!\n");
}

.fi
.PP

.IP "5." 4
Fill 'get_state_data()' function with code that will generate state information as defined in the data model\&. 
.PP
.nf
char * get_state_data(char * model, char * running, struct nc_err **err)
{
        return strdup("<?xml version="1\&.0"?><toaster xmlns="http://netconfcentral\&.org/ns/toaster"> \&.\&.\&. </toaster>");
}

.fi
.PP

.IP "6." 4
Complete the configuration callbacks\&. The 'op' parameter may be used to determine operation which was done with the node\&. Parameter 'node' holds a copy of node after change (or before change if op == XMLDIFF_REM)\&. 
.PP
.nf
int callback_toaster_toaster (void ** data, XMLDIFF_OP op, xmlNodePtr node, struct nc_err** error)
{
        switch(op) {
        case XMLDIFF_ADD:
                status = ON;
                break;
        case XMLDIFF_REM:
                status = OFF;
                break;
        default:
                *error = nc_err_new(NC_ERR_OP_FAILED);
                nc_err_set(*error, NC_ERR_PARAM_MSG, "Unsupported operation\&.");
                return(EXIT_FAILURE);
        }
        return(EXIT_SUCCESS);
}

.fi
.PP

.IP "7." 4
Fill the RPC message callback functions with code that will be run when a message arrives\&. 
.PP
.nf
nc_reply * rpc_make_toast (xmlNodePtr input[])
{
        xmlNodePtr toasterDoneness = input[0];
        xmlNodePtr toasterToastType = input[1];

        nc_reply * reply;
        int doneness = atoi(xmlNodeGetContent(toasterDoneness));

        if (status == ON) {
                status = BUSY;
                pthread_create(&thread, NULL, auxiliary_make_toast, (void*)&doneness);
                pthread_detach(thread);
                reply = nc_reply_ok();
        } else {
                reply = nc_reply_error(nc_err_new(NC_ERR_OP_FAILED));
        }
        return(reply);
}

.fi
.PP
 
.PP
.nf
nc_reply * rpc_cancel_toast (xmlNodePtr input[])
{
        nc_reply * reply;

        if (status == BUSY) {
                status = ON;
                ncntf_event_new(-1, NCNTF_GENERIC, "<toastDone><toastStatus>canceled</toastStatus></toastDone>");
                reply = nc_reply_ok();
        } else {
                reply = nc_reply_error(nc_err_new(NC_ERR_OP_FAILED));
        }
        return(reply);
}

.fi
.PP

.PP
.PP
.SS "Compiling module"
.PP
Following sequence of commands will produce the shared library 'toaster\&.so' which may be loaded into libnetconf: 
.PP
.nf
$ autoreconf
$ \&./configure
$ make

.fi
.PP
.PP
.SS "Integrating to a server"
.PP
In a server we use libnetconf's function \fBncds_new_transapi()\fP instead of \fBncds_new()\fP to create a transAPI-capable data store\&. Then, you do not need to process any data-writing (edit-config, copy-config, delete-config, lock, unlock), data-reading (get, get-config) or module data-model-defined RPC operations\&. All these operations are processed inside the \fBncds_apply_rpc2all()\fP function\&. 
